﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using FinosServiceLibrary.Server;
using FinosLibrary;
namespace FinosServiceLibrary.Server {
    public class AppManager {
        public static Dictionary<string, App> apps = new Dictionary<string, App>();
        public static string AppDir = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "applications";
        public static string[] appnames {
            get { return apps.Keys.Where(name => !name.Contains('/')).ToArray(); }
        }
        public static string[] GetInstanceList(string app) {
            return apps.Keys.Where(name => name.Contains('/') && name.Split('/')[0] == app).Select(name => name.Split('/')[1]).ToArray();
        }
        public static void ListApp() {
            if(!Directory.Exists(AppDir)){
                Directory.CreateDirectory(AppDir);
            }
            string[] files = Directory.GetDirectories(AppDir);
            foreach (string i in files) {
                App app = new App { path = i, roomName = "" };
                if (!apps.ContainsKey(app.name)) {
                    apps.Add(app.name, app);
                }
            }
        }
        public static bool ConnectApp(Client client, string name) {
            string[] fullname = name.Split('/');
            if (name == "") return true;
            if (apps.ContainsKey(fullname[0])) {
                if (!apps.ContainsKey(name)) {
                    apps.Add(name, new App { path = apps[fullname[0]].path, roomName = fullname[1] });
                    AdminClient.broadcast("GotInstanceList", new Package(fullname[0], GetInstanceList(fullname[0])));
                }
                if (apps[name].appDomain == null) {
                    try {
                        StartupApp(name);
                        Logger.trace("成功启动模块："+name);
                    } catch (Exception e) {
                        e.LoggerE();
                        return false;
                    }
                }
                var oldApps = apps.Values.Where(x => x.ContainClient(client.id));
                foreach (var oldApp in oldApps) {
                    oldApp.loader.onDisconnect(client.id);
                }
                apps[name].loader.addClient(client.id);
                client.appBelong = apps[name].loader;
                return true;
            }
            return false;
        }
        public static void StartupApp(string name) {
            if (apps.ContainsKey(name)) {
                apps[name].loadApp();
            }
        }
        public static void StopApp(string name) {
            if (apps.ContainsKey(name) && apps[name].appDomain != null)
                apps[name].stop();
        }
        public static void DeleteApp(string name) {
            StopApp(name);
            Logger.trace("删除模块：" + AppDir + "/" + name);
            if (apps[name].original) {
                Directory.Delete(AppDir + "/" + name, true);
            }
            apps.Remove(name);
        }
    }
    public class App : FMarshalByRefObject {
        public string path;
        public string roomName;
        public AppDomain appDomain;
        public AppLoader loader;
        public Client getClientByID(string id) {
            return Client.getClientByID(id);
        }
        public void TraceMessage(string[] msg) {
            if (original) return;
            AdminClient.TraceMessage(fullname, msg);
        }
        public bool ContainClient(string clientId) {
            return loader!=null&&loader.clients.Contains(clientId);
        }
        public string[] appclients {
            get {
                if (loader == null || loader.clients == null) {
                    return new string[] { };
                }
                return loader.clients.ToDictionary<string, string>(client => { return "[" + client + "]" + getClientByID(client).remoteEndPoint.ToString(); }).Keys.ToArray();
            }
        }
        public void AddClient(string id) {
            if (original) return;
            AdminClient.broadcast("AddClient", new string[] { fullname, "[" + id + "]" + getClientByID(id).remoteEndPoint.ToString() });
        }
        public void RemoveClient(string id) {
            if (original) return;
            AdminClient.broadcast("RemoveClient", new string[] { fullname, "[" + id + "]" + getClientByID(id).remoteEndPoint.ToString() });
        }
        public string name {
            get {
                if (path != null) {
                    return new DirectoryInfo(path).Name;
                } else {
                    return "管理模块";
                }
            }
        }
        public bool original { get { return roomName == ""; } }
        public string fullname { get { return original ? name : name + "/" + roomName; } }
        public void loadApp<T>() {
            loader = new AppLoader() { appBelong = this };
            loader.start(typeof(T));
        }
        public void loadApp() {
            if (appDomain != null) {
                stop();
            }
            appDomain = AppDomain.CreateDomain(fullname, null, new AppDomainSetup() { ShadowCopyFiles = "true", ShadowCopyDirectories = path });
            loader = appDomain.CreateInstanceAndUnwrap(Assembly.GetExecutingAssembly().GetName().FullName, typeof(AppLoader).FullName) as AppLoader;
            loader.appBelong = this;
            loader.LoadAssembly(path + "\\" + name + ".dll");
        }
        public void restart() {
            stop();
            loadApp();
        }
        public void stop() {
            string[] ids = loader.clients.ToArray();
            foreach (string id in ids) {
                Client.getClientByID(id).onDisconnect();
            }
            AppDomain.Unload(appDomain);
            appDomain = null;
        }
    }
}
